<template>
  <el-dialog
    append-to-body
    top="30px"
    width="800px"
    :before-close="beforeClose"
    :title="title"
    :close-on-click-modal="false"
    :visible.sync="visible"
  >
    <form
      novalidate
      v-loading="loading"
      class="my-3"
      ref="form"
      :class="{ 'was-validated': wasValidated }"
    >
      <div v-for="(item, key) in formList" :key="key">
        <div v-if="!item.hide">
          <div v-if="'text,number'.indexOf(item.type) > -1" class="form-group row">
            <label class="col-sm-2 col-form-label" :for="key">
              <span v-if="item.required" class="text-danger mr-1">*</span>
              <span>{{ item.label }}</span>
            </label>
            <div class="col-sm-10">
              <div :class="{ 'input-group': item.unit }">
                <input
                  v-model="item.value"
                  class="form-control"
                  min="0"
                  :class="{ 'form-control-ml': !item.maxWidth }"
                  :disabled="item.disabled"
                  :id="key"
                  :placeholder="`请输入${item.label}`"
                  :required="item.required"
                  :step="item.step || 0.0001"
                  :type="item.type"
                  v-bind="item.attrs"
                  @input="item.onInput(key, item.value, formList)"
                />
                <div v-if="item.unit" class="input-group-append">
                  <span class="input-group-text">{{ item.unit || '' }}</span>
                </div>
                <div class="invalid-feedback">{{ `请输入正确的${item.label}` }}</div>
              </div>
            </div>
          </div>

          <div
            v-if="'year/month/date/week/datetime/datetimerange/daterange'.indexOf(item.type) > -1"
            class="form-group row"
          >
            <label class="col-sm-2 col-form-label" :for="key">
              <span v-if="item.required" class="text-danger mr-1">*</span>
              <span>{{ item.label }}</span>
            </label>
            <div class="col-sm-10">
              <el-date-picker
                v-model="item.value"
                :type="item.type"
                :style="{ minWidth: '360px' }"
                :disabled="item.disabled"
                :id="key"
                :placeholder="`请选择${item.label}`"
                v-bind="item.attrs"
                @input="v => handleDateChange(v, item, key)"
              ></el-date-picker>
              <div class="invalid-feedback">{{ `请输入正确的${item.label}` }}</div>
            </div>
          </div>

          <fieldset v-else-if="'radio' === item.type" class="form-group">
            <div class="row">
              <legend class="col-form-label col-sm-2 pt-0">
                <span v-if="item.required" class="text-danger mr-1">*</span>
                <span>{{ item.label }}</span>
              </legend>
              <div class="col-sm-10">
                <div
                  v-for="(value, rKey, index) in item.enumType"
                  class="form-check"
                  :class="{ 'form-check-inline': item.inline }"
                  :key="index"
                >
                  <input
                    v-model="item.value"
                    class="form-check-input"
                    :disabled="item.disabled"
                    :id="`${key}${index}`"
                    :name="`${key}`"
                    type="radio"
                    :value="rKey"
                    @click="item.onClick(rKey, formList)"
                  />
                  <label class="form-check-label" :for="`${key}${index}`">{{ value }}</label>
                </div>
              </div>
            </div>
          </fieldset>

          <fieldset v-else-if="'checkbox' === item.type" class="form-group">
            <div class="row">
              <legend class="col-form-label col-sm-2 pt-0">
                <span v-if="item.required" class="text-danger mr-1">*</span>
                <span>{{ item.label }}</span>
              </legend>
              <div class="col-sm-10">
                <div
                  v-for="(value, rKey, index) in item.enumType"
                  class="form-check"
                  :class="{ 'form-check-inline': item.inline }"
                  :key="index"
                >
                  <input
                    v-model="item.value"
                    class="form-check-input"
                    :disabled="item.disabled"
                    :id="`${key}${index}`"
                    :name="`${key}`"
                    type="checkbox"
                    :value="rKey"
                    @click="item.onClick(rKey, formList)"
                  />
                  <label class="form-check-label" :for="`${key}${index}`">{{ value }}</label>
                </div>
              </div>
            </div>
          </fieldset>

          <div v-else-if="'textarea' === item.type" class="form-group row">
            <label class="col-sm-2 col-form-label" :for="key">
              <span v-if="item.required" class="text-danger mr-1">*</span>
              <span>{{ item.label }}</span>
            </label>
            <div class="col-sm-10">
              <textarea
                v-model="item.value"
                class="form-control"
                :class="{ 'form-control-ml': !item.maxWidth }"
                :disabled="item.disabled"
                :id="key"
                :placeholder="`请输入${item.label}`"
                :required="item.required"
                :rows="item.rows"
              ></textarea>
              <div class="invalid-feedback">{{ `请输入正确的${item.label}` }}</div>
            </div>
          </div>

          <div v-else-if="item.type === 'select'" class="form-group row">
            <label class="col-sm-2 col-form-label" :for="key">
              <span v-if="item.required" class="text-danger mr-1">*</span>
              <span>{{ item.label }}</span>
            </label>
            <div class="col-sm-10">
              <select
                v-model="item.value"
                class="form-control"
                :class="{ 'form-control-ml': !item.maxWidth }"
                :disabled="item.disabled"
                :id="key"
              >
                <option disabled v-show="!item.value" value="">{{ `请选择${item.label}` }}</option>
                <option v-for="(value, rKey, index) in item.enumType" :key="index" :value="rKey">
                  {{ value }}
                </option>
              </select>
            </div>
          </div>

          <div v-else-if="item.type === 'image'" class="form-group row">
            <label class="col-sm-2 col-form-label" :for="key">
              <span v-if="item.required" class="text-danger mr-1">*</span>
              <span>{{ item.label }}</span>
            </label>
            <div class="col-sm-10">
              <upload-oss
                multiple
                accept="image/*"
                listType="picture-card"
                :file-list="item.fileList"
                :id="key"
                :on-complete="images => handleImagesComplete(key, images)"
                :ref="key"
              ></upload-oss>
            </div>
          </div>

          <div v-else-if="item.type === 'component'" class="form-group row">
            <label class="col-sm-2 col-form-label" :for="key">
              <span v-if="item.required" class="text-danger mr-1">*</span>
              <span>{{ item.label }}</span>
            </label>
            <div class="col-sm-10">
              <component
                v-bind="item.attrs"
                v-model="item.value"
                v-on="item.on"
                :is="item.component"
              ></component>
            </div>
          </div>

          <div v-else-if="item.type === 'dropdown'" class="form-group row">
            <label class="col-sm-2 col-form-label" :for="key">
              <span v-if="item.required" class="text-danger mr-1">*</span>
              <span>{{ item.label }}</span>
            </label>
            <div class="col-sm-10">
              <el-autocomplete
                v-model="item.value"
                class="w-100"
                :class="{ 'form-control-ml': !item.maxWidth }"
                :disabled="item.disabled"
                :fetch-suggestions="(s, cb) => querySearch(s, cb, item.enumType)"
                :placeholder="`请选择或输入${item.label}`"
                :required="item.required"
                @select="v => handleDropdownSelect(v, key)"
              ></el-autocomplete>
              <div v-if="item.required" class="invalid-feedback">
                {{ `请选择或输入${item.label}` }}
              </div>
            </div>
          </div>
        </div>
      </div>
    </form>
    <slot name="table"></slot>
    <div class="row mt-5">
      <div class="col-sm-10 offset-sm-2">
        <el-button class="btn-long" type="primary" :loading="saveLoading" @click="onSubmit">
          保存
        </el-button>
        <slot name="button"></slot>
      </div>
    </div>
  </el-dialog>
</template>
<script>
import { PATTERN_PHONE, PATTERN_ID_CARD } from '@/common/plugins/constant'
import { arrayFromString } from '@vimi/utils-tool'

export default {
  components: {},
  props: {
    visible: Boolean,
    service: {
      type: String,
      default: 'credit',
    },
    tableName: {
      type: String,
      required: true,
    },
    formData: {
      type: Object,
      required: true,
    },
    tableId: String,
    Appendserviceid: {
      type: Boolean,
      default: false,
    },
    tableData: Object,
    autoInit: {
      type: Boolean,
      default: true,
    },
    formAppend: {
      type: Object,
      default: () => {
        return {
          customer_id: 'customer_id',
          customer_name: 'farm_name',
        }
      },
    },
    idAppend: {
      type: Boolean,
      default: true,
    },
    beforeSave: Function,
    title: String,
  },
  data() {
    return {
      wasValidated: false,
      loading: false,
      saveLoading: false,
      status: '',
      customerRelatedId: '',
      customerData: {},
      form: {},
      formList: {},
      imgUploadCount: 0,
      imgUploadTotal: 0,
      imgUploadKeys: [],
      validatorList: {
        phone: PATTERN_PHONE,
        idCard: PATTERN_ID_CARD,
      },
    }
  },
  computed: {
    clientId() {
      return this.$store.getters.org.clientId
    },
  },
  watch: {
    formData: {
      handler: function () {
        this.init()
      },
      deep: true,
    },
    tableData: {
      handler: function () {
        this.init()
      },
      deep: true,
    },
    visible(val) {
      if (val) {
        this.init()
      }
    },
  },
  created() {
    this.customerRelatedId =
      this.$route.query.id || sessionStorage.getItem('customer_related_id') || ''
    if (this.autoInit) {
      this.init()
    }
  },
  mounted() {},
  methods: {
    beforeClose() {
      this.$emit('update:visible', false)
      this.wasValidated = false
      this.initForm()
    },

    init() {
      this.getCustomerData()
      this.initForm()
      this.getData()
    },

    initForm() {
      this.imgUploadKeys = []
      this.imgUploadTotal = 0
      this.formList = {}
      Object.keys(this.formData).forEach(key => {
        this.formList[key] = { ...this.formData[key] }
        const type = this.formList[key].type
        if (type === 'image') {
          this.imgUploadTotal++
          this.imgUploadKeys.push(key)
        } else if ('radio,checkbox'.indexOf(type) > -1) {
          const onClick = this.formList[key].onClick
          this.formList[key].onClick = typeof onClick === 'function' ? onClick : () => {}
        } else if ('text,number'.indexOf(type) > -1) {
          const onInput = this.formList[key].onInput
          this.formList[key].onInput = typeof onInput === 'function' ? onInput : () => {}
          // 验证器
          const validator = this.formList[key].validator
          if (validator) {
            if (this.formList[key].attrs) {
              this.formList[key].attrs.pattern = this.validatorList[validator] || validator
            } else {
              this.formList[key].attrs = {
                pattern: this.validatorList[validator] || validator,
              }
            }
          }
        } else if ('year/month/date/week/datetime/datetimerange/daterange'.indexOf(type) > -1) {
          const onInput = this.formList[key].onInput
          this.formList[key].onInput = typeof onInput === 'function' ? onInput : () => {}
          if (type === 'date') {
            if (this.formList[key].attrs) {
              if (!this.formList[key].attrs.valueFormat) {
                this.formList[key].attrs.valueFormat = 'yyyy-MM-dd'
              }
            } else {
              this.formList[key].attrs = { valueFormat: 'yyyy-MM-dd' }
            }
          }
        }
      })
    },

    getCustomerData() {
      const localCustomerData = sessionStorage.getItem('customer_related_view')
      try {
        this.customerData = JSON.parse(localCustomerData)
      } catch (e) {
        console.error(e)
      }
    },

    async getData() {
      let data = {}

      if (this.tableData) {
        // 取传入数据
        data = { ...this.tableData }
      } else {
        // 没有传入数据，api取数据，否则就是新增数据
        if (!this.tableId) {
          return
        }

        this.loading = true
        const [res] = await this.$utils.promise(
          this.$api.getDataFromId(this.service, this.tableName, this.tableId)
        )
        this.loading = false

        if (!(res && res.data)) {
          return
        }

        data = res.data
      }

      this.convertEditData(data)
    },

    convertEditData(data) {
      Object.keys(this.formList).forEach(key => {
        const type = this.formList[key].type
        let value = data[key]
        if (type === 'date') {
          value = value ? value.substring(0, 10) : value
        } else if (type === 'image') {
          this.formList[key].fileList = this.imgToFileList(value)
        } else if (type === 'number') {
          value = this.pureNumber(value)
        } else if (type === 'radio') {
          this.formList[key].onClick(value, this.formList)
        }
        const hv = this.formList[key].hide
        this.formList[key].hide = typeof hv === 'function' ? hv(value, data, key) : hv
        if (value !== undefined) {
          this.formList[key].value = value
        }
      })
    },

    onSubmit() {
      this.wasValidated = true
      const form = this.$refs.form
      if (!form.checkValidity()) {
        return this.$message.error('输入错误，请检查您的输入！')
      }

      if (this.imgUploadTotal) {
        this.imgUploadCount = 0
        for (const upKey of this.imgUploadKeys) {
          const ref = this.$refs[upKey]
          if (ref && ref.length) {
            ref[0].submit()
          }
        }
      } else {
        this.saveData()
      }
    },

    handleImagesComplete(key, images) {
      this.formList[key].value = this.getImageString(images)
      this.imgUploadCount++
      if (this.imgUploadCount >= this.imgUploadTotal) {
        this.saveData()
      }
    },

    saveData() {
      this.form = {}
      if (this.idAppend) {
        this.form.customer_related_id = this.customerRelatedId
      }
      if (this.formAppend && this.customerData) {
        Object.keys(this.formAppend).forEach(key => {
          this.form[key] = this.customerData[this.formAppend[key]]
        })
      }
      Object.keys(this.formList).forEach(key => {
        const value = this.formList[key].value
        const type = this.formList[key].type
        // const hide = this.formList[key].hide
        const redundancy = this.formList[key].redundancy
        // 过滤空值
        if (!('number,date,month'.indexOf(type) > -1 && !value) && !this.formList[key].redun) {
          this.form[key] = this.formList[key].value
        }
        // 冗余字段计算
        if (redundancy && typeof redundancy === 'function') {
          this.form[key] = redundancy(this.formList, key, value)
        }
      })

      if (this.beforeSave) {
        const change = this.beforeSave()
        if (change && change.then) {
          change
            .then(() => {
              this.toSave()
            })
            .catch(() => {
              if (this.status === '403') {
                this.status = '403'
                return this.$message.error('还没有给您授权，请找相关部门负责人！')
              } else {
                return this.$message.error('保存失败！请重试！')
              }
            })
        } else {
          this.toSave()
        }
      } else {
        this.toSave()
      }
    },

    toSave() {
      if (this.tableId) {
        this.putData()
      } else {
        this.postData()
      }
    },

    async postData() {
      if (this.Appendserviceid) {
        this.form['service_id'] = this.clientId
      }
      this.saveLoading = true
      const [res, err] = await this.$utils.promise(
        this.$api.addData(this.service, this.tableName, this.form)
      )
      this.saveLoading = false
      if (res) {
        this.$message.success('数据采集成功！')
        this.$emit('success')
        this.beforeClose()
      } else {
        // this.$message.error(`数据采集失败，请重试！（${err.status}）`)
        if (err && err.status === 403) {
          this.status = '403'
          return this.$message.error('还没有给您授权，请找相关部门负责人！')
        } else {
          return this.$message.error('保存失败！请重试！')
        }
      }
    },

    async putData() {
      this.saveLoading = true
      const [res, err] = await this.$utils.promise(
        this.$api.updateData(this.service, this.tableName, this.tableId, this.form)
      )
      this.saveLoading = false
      if (res) {
        this.$message.success('修改数据成功！')
        this.$emit('success')
        this.beforeClose()
      } else {
        // return this.$message.error('还没有给您授权，请找相关部门负责人！')
        if (err && err.status === '403') {
          this.status = '403'
          return this.$message.error('还没有给您授权，请找相关部门负责人！')
        } else {
          return this.$message.error('保存失败！请重试！')
        }
      }
    },

    setKey(key, attr, value, defaultValue) {
      this.formList[key][attr] = value
      if (defaultValue) {
        this.formList[key].value = defaultValue
      }
      this.$set(this, 'formList', { ...this.formList })
    },

    imgToFileList(images = '') {
      return arrayFromString(images).map(item => {
        return { name: '', url: item }
      })
    },

    getImageString(images = []) {
      return images && images.length ? `["${images.map(item => item.url).join('","')}"]` : ''
    },

    pureNumber(value) {
      return typeof value === 'string' ? value.replace(/\.0*$/g, '') : value
    },

    querySearch(s, cb, list) {
      const arr = Object.keys(list).map(key => {
        return { value: list[key] }
      })
      cb(!s ? arr : arr.filter(item => item.value.indexOf(s) > -1))
    },

    handleDropdownSelect(item, key) {
      this.setKey(key, 'value', item.value)
    },

    handleDateChange(v, item, key) {
      this.setKey(key, 'value', v)
      item.onInput(key, v, this.formList)
    },
  },
}
</script>
<style scoped></style>
